/**  
  -- The Performance Driven Lime Project -- 

  A self adaptive tuple space for mobile agents and hosts by dynamic
  adapting tuple's replication policy.
  
  Copyright (C) 2008
  Xing Jiankuan, Pan Wenhui
  SAGroup of Tsinghua University

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received this copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 */
package sagroup.dracots;

import lime2.LimeTupleSpace;
import lime2.LimeWrapper;
import lime2.Location;
import lime2.TupleID;
import sagroup.dracots.TupleType;

/**
 * Tuple that tends to share among agents. A share tuple that is written
 * directly by "out" or "outg" is a <b>master</b>. And its additional copy is
 * master's <b>replica</b>. Logically, masters and their replicas are
 * equivalent. In this class, tuples have version and can be replicated.
 * Therefore, agents can distribute them as needs, such as to improve
 * performance. Some fields are added to added enabling replicas to track back
 * to its master.
 * 
 * @author Xing Jiankuan
 * 
 */
public class ShareTuple extends DracoTuple {

	private static final long serialVersionUID = -4985251599542052490L;

	/**
	 * Tuple's version
	 */
	@Field
	Long ver = new Long(DracoConstants.INITIAL_VER_NUM);

	/**
	 * Master's current location. If this tuple is a master, this field is null.
	 */
	@Field
	Location masterCurr;

	/**
	 * Master's destination location. If this tuple is a master, this field is
	 * null.
	 */
	@Field
	Location masterDest;

	/**
	 * Indicate whether this tuple is a master or a replica.
	 */
	@Field
	Boolean isReplica;
	
	/**
	 * Indicate whether this replica is vilid. This field is mainly used 
	 * in CO policy.  
	 * Note that users can't set this field manually. Instead, it will be defined 
	 * by system.
	 */
//	@Field
//	Boolean isValid = true;

	public ShareTuple() {
		// empty constructor
	}

	/**
	 * Construct a new TVRLimeWrapper. The LimeTuple's fields tuple ID and
	 * current location are generated automatically
	 * 
	 * @param type
	 *            tuple type
	 * @param vid
	 *            version layered ID
	 * @param ver
	 *            version
	 * @param dest
	 *            destination location
	 * @param masterCurr
	 *            current location of master
	 * @param masterDest
	 *            destination location of master
	 * @param isReplica
	 *            indicate master or replica
	 * @param tuple
	 *            the tuple containing user data
	 */
	public ShareTuple(TupleType type, TupleID vid, Long ver, Location masterCurr, Location masterDest, Boolean isReplica) {
		this(LimeTupleSpace.nextTID(), Location.HERE, Location.HERE, type, vid, ver,
				masterCurr, masterDest, isReplica);
	}

	public ShareTuple(TupleID tid, Location curr, Location dest,
			TupleType type, TupleID vid, Long ver, Location masterCurr,
			Location masterDest, Boolean isReplica) {
		super(tid, curr, dest, type, vid);
		this.ver = ver;
		this.masterCurr = masterCurr;
		this.masterDest = masterDest;
		this.isReplica = isReplica;
	}
	
	public ShareTuple(TupleID tid, Location curr, Location dest,
			TupleType type, TupleID vid) {
		super(tid, curr, dest, type, vid);
		this.ver = DracoConstants.INITIAL_VER_NUM;
		this.masterCurr = Location.INVALID;
		this.masterDest = Location.INVALID;
		this.isReplica = false;
	}
	/**
	 * The template that can match any local replica
	 */
	public static final ShareTuple ALLREPLICA;
	static {
		ALLREPLICA = (ShareTuple) DracoTuple.createMatchAllTemplateByClass(ShareTuple.class);
		ALLREPLICA.setReplica(true);
	}
	
	/**
	 * Transfer all meta data of ShareTuple(including DracoTuple) 
	 * in this tuple to target
	 * @param target
	 * @author Xing Jiankuan
	 */
	public void transferMetaData(ShareTuple target) {
		
		target.limeWrapper = this.limeWrapper;
		target.isMatchAll = this.isMatchAll;
		target.type = this.type;
		target.vid = this.vid;
		target.ver = this.ver;
		target.masterCurr = this.masterCurr;
		target.masterDest = this.masterDest;
		target.isReplica = this.isReplica;
	}
	
	/**
	 * Facility to replicate a master. Only fields for tuple are replicated
	 * 
	 * @param master
	 *            the tuple to be replicated
	 * @param dest
	 *            the destination of replica
	 * @return master's replica
	 * @author Xing Jiankuan
	 */
	public ShareTuple replicate(Location dest) {
		ShareTuple ret = null;
		if(this.isMatchAll) {
			throw new IllegalArgumentException("Cannot replicate a match-all template");
		}
		try {
			ret = (ShareTuple) this.clone();
			ret.limeWrapper = new LimeWrapper(LimeTupleSpace.nextTID(), Location.HERE,
					dest, DracoTuple.DUMMY_TUPLE);
			ret.masterCurr = this.limeWrapper.cur;
			ret.masterDest = this.limeWrapper.dest;
			ret.isReplica = Boolean.TRUE;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return ret;
	}	

	public Long getVer() {
		return ver;
	}

	public void setVer(Long ver) {
		this.ver = ver;
	}

	public boolean isOlderThen(ShareTuple t) {
		return this.getVer().longValue() < t.getVer().longValue();
	}

	public Location getMasterCurr() {
		return masterCurr;
	}

	public void setMasterCurr(Location masterCurr) {
		this.masterCurr = masterCurr;
	}

	public Location getMasterDest() {
		return masterDest;
	}

	public void setMasterDest(Location masterDest) {
		this.masterDest = masterDest;
	}

	public Boolean isReplica() {
		return isReplica;
	}

	public void setReplica(boolean isReplica) {
		this.isReplica = isReplica;
	}

//	public Boolean isValid() {
//		return isValid;
//	}
//	
//	public void setValid(boolean isValid) {
//		this.isValid = isValid;
//	}
	/**
	 * Judge whether a tuple's master is here
	 * 
	 * @Effects: If original and belong to HERE , return true;<br>
	 *           Else, false;
	 * 
	 */
	boolean isMasterLocal() {
		if (isMaster() && masterCurr != null && masterCurr.isHere()
				&& masterDest != null && masterDest.isHere()
				&& limeWrapper.cur != null && limeWrapper.cur.isHere()
				&& limeWrapper.dest != null && limeWrapper.dest.isHere()) {

			return true;
		} else {
			return false;
		}
	}

	/**
	 * Judge whether a tuple is a master or replica
	 * 
	 * @Effects: If isReplica is true, return true;<br>
	 *           Else, false;
	 */
	public boolean isMaster() {
		if (isReplica != null && !isReplica.booleanValue()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Create a template matching a share tuple with specified version layer ID
	 * 
	 * @param vid
	 *            the version layer ID to be matched
	 * @return the constructed ShareTuple instance
	 * @author Xing Jiankuan
	 */
	public static ShareTuple createVIDTemplate(TupleID vid) {
		ShareTuple t = new ShareTuple(null, Location.UNSPECIFIED, Location.UNSPECIFIED,
				null, vid, null, Location.UNSPECIFIED, Location.UNSPECIFIED,
				null);
		t.setMatchAll(true);
		return t;
	}

	/**
	 * Create a template matching a share tuple with specified tuple type
	 * 
	 * @param type
	 *            
	 * @return the constructed ShareTuple instance
	 * @author Huang Xiaodong
	 */
	public static ShareTuple createTypeTemplate(TupleType type) {
		ShareTuple t = new ShareTuple(null, Location.UNSPECIFIED, Location.UNSPECIFIED,
				type, null, null, Location.UNSPECIFIED, Location.UNSPECIFIED,
				null);
		t.setMatchAll(true);
		return t;
	}
	
	/**
	 * Create a template matching a share tuple with specified tuple type
	 * which is local.
	 * @param type
	 * @return
	 * @author Xing Jiankuan
	 */
	public static ShareTuple createLocalTypeTemplate(TupleType type) {
		ShareTuple t = new ShareTuple(null, Location.HERE, Location.HERE,
				type, null, null, Location.UNSPECIFIED, Location.UNSPECIFIED,
				null);
		t.setMatchAll(true);
		return t;
	}
	
	/**
	 * Create a template matching a replica with specified tuple type
	 * @param type the tuple type to be matched
	 * @return the template that can match replica with specified type
	 * @author Xing Jiankuan
	 */
	public static ShareTuple createReplicaTypeTemplate(TupleType type) {
		ShareTuple template = createTypeTemplate(type);
		template.isReplica = true;
		return template;
	}

	public String toString() {
		return super.toString()
				+ String.format(
						";ver=%d;replica=%b;masterCurr=%s;masterDest=%s", ver
								.longValue(), isReplica.booleanValue(),
						masterCurr.toString(), masterDest.toString());
	}
}
